package com.woniuxy.auth.filter;/*
@author houguai
@create 2021-03-03 15:56
*/

import com.fasterxml.jackson.databind.ObjectMapper;
import com.woniuxy.auth.jwt.Audience;
import com.woniuxy.auth.jwt.JwtUtil;
import com.woniuxy.auth.shiro.JwtToken;
import com.woniuxy.ticketcommon.ResponceResult;
import javafx.application.Application;
import lombok.extern.slf4j.Slf4j;

import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.AccessControlFilter;
import org.apache.shiro.web.filter.authc.AuthenticatingFilter;
import org.apache.shiro.web.util.WebUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;

import javax.annotation.Resource;
import javax.servlet.Filter;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Date;
import java.util.Map;
import java.util.Objects;

/**
 * 自定义过滤器
 */
@Slf4j
public class JwtFilter extends AuthenticatingFilter {

    @Autowired
    @Resource
    public ApplicationContext applicationContext;
    //10分钟后刷新token
    private static final int tokenRefreshInterval = 60 * 10;
    @Autowired
    private Audience audience;

    //创建token
    @Override
    protected AuthenticationToken createToken(ServletRequest request, ServletResponse response) throws Exception {
        String jwtToken = ((HttpServletRequest) request).getHeader("jwt");
        return new JwtToken(jwtToken);

    }

    //通过时的方法
    @Override
    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
        if (this.isLoginRequest(request, response))
            return true;
        boolean allowed = false;
        try {
            allowed = executeLogin(request, response);
        } catch (IllegalStateException e) { // not found any token
            log.error("Not found any token");
        } catch (Exception e) {
            log.error("Error occurs when login", e);
        }
        ShiroFilterFactoryBean shiroFilterFactoryBean=applicationContext.getBean(ShiroFilterFactoryBean.class);
        response.setContentType("application/json");

        //在这直接进行处理
        try {
            if (allowed){
                //获取到当前访问的URL
                String url = ((HttpServletRequest) request).getRequestURL().toString();
                //获取该URL所需经过的过滤器的类

                //根据过滤器名字找到具体的过滤器的类
                //判断当前的过滤器类是否是该URL所需过滤器中的最后一个
                //if(是最后一个) return false
                //else return true
                if (url.contains("?")){
                    url.replace("?","|");
                    url = url.split("|")[0];
                    url=url.replace("//","/");
                    String[] split = url.split("/");
                    url="";
                    for(int i=2;i<split.length;i++){
                        url+="/"+split[i];
                    }
                }else {
                    //没有参数在路径中
                    url=url.replace("//","/");
                    String[] split = url.split("/");
                    url="";
                    for(int i=2;i<split.length;i++){
                        url+="/"+split[i];
                    }
                }
               Map<String, String> filterMap = shiroFilterFactoryBean.getFilterChainDefinitionMap();
               String[] filters = filterMap.get(url+"").replaceAll("(\\[(.*?)])", "").split(",");  //  jwt,perms[]
               Map<String, Filter> map = shiroFilterFactoryBean.getFilters();
               Filter lastFilter=map.get(filters[filters.length-1]);
               if (lastFilter.getClass()==this.getClass()){

//                   ResponceResult<Void> result = new ResponceResult<>(200, "成功");
//                   ObjectMapper objectMapper = new ObjectMapper();
//                   response.getWriter().write(objectMapper.writeValueAsString(result));
                   return true;
               }else {
               }
            }else {
                ResponceResult<Void> result = new ResponceResult<>(403, "会话失效，重新登录");
                ObjectMapper objectMapper = new ObjectMapper();
                response.getWriter().write(objectMapper.writeValueAsString(result));
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        return false;
    }

    //当登录成功
    @Override
    protected boolean onLoginSuccess(AuthenticationToken token, Subject subject, ServletRequest request, ServletResponse response) throws Exception {

        HttpServletResponse httpResponse = WebUtils.toHttp(response);

//        if (token instanceof JwtToken && "jwt".equalsIgnoreCase(((JwtToken) token).getCredentials().toString())) {
//            JwtToken jwtToken = (JwtToken) token;
//            boolean shouldRefresh = shouldTokenRefresh(Objects.requireNonNull(JwtUtil.getAccount(jwtToken.,audience.getBase64Secret()));
//            if (shouldRefresh) {
//                //生成新的TOKEN
//                SecurityUser user = (SecurityUser) subject.getPrincipal();
//                String newToken = JwtUtil.createJWT(user.getUserInfo().getId());
//                httpResponse.setHeader("x-auth-token", newToken);
//            }
//        }
       //为jwt自动续期
        return super.onLoginSuccess(token, subject, request, response);
    }

    //只让onPreHandle返回通过的
    @Override
    public boolean onPreHandle(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception {
        return isAccessAllowed(request,response,mappedValue);
    }

    //验证失败的方法
    @Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {

        ResponceResult<Void> result = new ResponceResult<>(403, "会话失效，重新登录");
        ObjectMapper objectMapper = new ObjectMapper();
        response.getWriter().write(objectMapper.writeValueAsString(result));


        return false;
    }

    /**
     * 判断是否需要刷新TOKEN
     * @param issueAt token签发日期
     * @return 是否需要刷新TOKEN
     */
    private boolean shouldTokenRefresh(Date issueAt) {
        LocalDateTime issueTime = LocalDateTime.ofInstant(issueAt.toInstant(), ZoneId.systemDefault());
        return LocalDateTime.now().minusSeconds(tokenRefreshInterval).isAfter(issueTime);
    }


}
